import { ref, shallowRef } from "vue";
import { cloneDeep, isObject } from "lodash-es";
import type { Ref, ShallowRef } from "vue";

type Reset<T> = {
  reset: (keys?: keyof T | string | keyof T[] | string[] | undefined) => void;
};

type ResetRef<F, K> = F extends Ref ? Ref<K> : ShallowRef<K>;

export type UseResetReturn<K, T> = K & Reset<T>;

function resetRefFactory<T>(resetRef: any) {
  function useResetRef<K>(initialValue?: K) {
    const result = resetRef(cloneDeep(initialValue)) as UseResetReturn<
      ResetRef<T, K>,
      K
    >;

    result.reset = (keys) => {
      const keyArr = Array.isArray(keys) ? keys : [keys];
      let newValue: any = undefined;

      if (!keys || keyArr.length === 0) {
        newValue = cloneDeep(initialValue);
      } else if (isObject(initialValue)) {
        newValue = {};
        keyArr.forEach((key) => {
          newValue[key] = cloneDeep(initialValue[key as keyof K]);
        });
      }

      result.value = newValue;
    };

    return result;
  }

  return useResetRef;
}

export const useResetRef = resetRefFactory<
  Ref & {
    reset: () => void;
  }
>(ref);

export const useResetShallowRef = resetRefFactory<ShallowRef>(shallowRef);
